Chapter 12
What's Caching?
Storing a response into a file and using it for future
Symfony's solution
You need to first enable caching in settings.yml

dev:
  .settings:
    cache:                  on
 
Frontend/modules/user/config/cache.yml
module: user action:list

list:
  enabled:     on
  with_layout: false   # Default value
  lifetime:    86400   # Default value
 
A complete one

list:
  enabled:    on
show:
  enabled:    on

all:
  with_layout: false   # Default value
  lifetime:    86400   # Default value
 
Partial, Component, Slots or Component Slots
Same
frontend/modules/user/config/cache.yml

_my_partial:
  enabled:    on
list:
  enabled:    on
...
 
It can handle parameters as well.

<?php include_partial('user/my_other_partial', array('foo' => 'bar')) ?>
 
Components

_day:
  enabled: on
 
Template dependent or not?

_day:
  contextual: true
  enabled:   on
 
part of a template
Example

<!-- Code executed each time -->
<?php echo link_to('last accessed user', 'user/show?id='.$last_accessed_user_id) ?>
 
<!-- Cached code -->
<?php if (!cache('users')): ?>
  <?php foreach ($users as $user): ?>
    <?php echo $user->getName() ?>
  <?php endforeach; ?>
  <?php cache_save() ?>
<?php endif; ?>
 
Or...

<?php if (!cache('users', 43200)): ?>
 

$context->getViewCacheManager()->addCache('article', 'show', array(
  'withLayout' => true,
  'lifeTime'   => 3600,
));
frontend/lib/conditionalCacheFilter.class.php

class conditionalCacheFilter extends sfFilter
{
  public function execute($filterChain)
  {
    $context = $this->getContext();
    if (!$context->getUser()->isAuthenticated())
    {
      foreach ($this->getParameter('pages') as $page)
      {
        $context->getViewCacheManager()->addCache($page['module'], $page['action'], array('lifeTime' => 86400));
      }
    }
 
    // Execute next filter
    $filterChain->execute();
  }
}
filters.yml

...
security: ~

conditionalCache:
  class: conditionalCacheFilter
  param:
    pages:
      - { module: article, action: show }

cache: ~
...
 
Where to store?
factories.yml

view_cache:
    class: sfFileCache
    param:
      automaticCleaningFactor: 0
      cacheDir:                %SF_TEMPLATE_CACHE_DIR%
 
You can also use apache-level caching for super-fast caching
The entire cache

// Erase the whole cache
> php symfony cache:clear

// Short syntax
> php symfony cc

// Erase only the cache of the frontend application
> php symfony cache:clear --app=frontend

// Erase only the HTML cache of the frontend application
> php symfony cache:clear --app=frontend --type=template

// Erase only the configuration cache of the frontend application
// The built-types are config, i18n, routing, and template.
> php symfony cache:clear --app=frontend --type=config

// Erase only the configuration cache of the frontend application and the prod environment
> php symfony cache:clear --app=frontend --type=config --env=prod
 
Selective Parts

public function executeUpdate($request)
{
  // Update a user
  $user_id = $request->getParameter('id');
  $user = UserPeer::retrieveByPk($user_id);
  $this->forward404Unless($user);
  $user->setName($request->getParameter('name'));
  ...
  $user->save();
 
  // Clear the cache for actions related to this user
  $cacheManager = $this->getContext()->getViewCacheManager();
  $cacheManager->remove('user/list');
  $cacheManager->remove('user/show?id='.$user_id);
  ...
}
Remove Partials
sf_cache_key is hard to memorize! Instead, define your own cache key:

<? include_partial('a1partial', array('i' => $i, 'sf_cache_key'=>$i)) ?>
...
<?php include_partial('user/my_partial', array(
  'user'         => $user,
  'sf_cache_key' => $user->getId()
) ?>
 
and remove it

$cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key='.$user->getId());
Removing Template Fragments

<!-- Cached code -->
<?php if (!cache('users')): ?>
  ... // Whatever
  <?php cache_save() ?>
<?php endif; ?>
 
// Is identified in the cache as
@sf_cache_partial?module=user&action=list&sf_cache_key=users
 
// Clear it with
$cacheManager->remove('@sf_cache_partial?module=user&action=list&sf_cache_key=users');
Cache dependencies
You need to be aware of caching problems.
Several Clearings at once

$cacheManager->remove('user/show?id=*');    // Remove for all user records


$cache->remove('user/show?sf_culture=*&id=12');


$cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key=*');    // Remove for all keys
Specify host

$cacheManager->remove('user/show?id=*');                     // Remove records for the current host and all users
$cacheManager->remove('user/show?id=*', 'life.askeet.com');  // Remove records for the host life.askeet.com and all users
$cacheManager->remove('user/show?id=*', '*');                // Remove records for every host and all users
 
Removing frontend cache from backend

$frontend_cache_dir = sfConfig::get('sf_cache_dir').DIRECTORY_SEPARATOR.'frontend'.DIRECTORY_SEPARATOR.sfConfig::get('sf_environment').DIRECTORY_SEPARATOR.'template';
$cache = new sfFileCache(array('cache_dir' => $frontend_cache_dir)); // Use the same settings as the ones defined in the frontend factories.yml
$cache->removePattern('user/show?id=12');
 
ETag
send as HTTP header, helps server to see if the content is modified, etc.

enbale it in symfony

all:
  .settings:
    etag: on
 
Last modified time
Server:

Last-Modified: Sat, 23 Nov 2006 13:27:31 GMT
 
Set it in symfony:

$this->getResponse()->setHttpHeader('Last-Modified', $this->getResponse()->getDate($timestamp));
 
Browser:

If-Modified-Since: Sat, 23 Nov 2006   13:27:31 GMT
 
Vary

Vary: Cookie
 
Symfony then caches depending on different parameters:

$this->getResponse()->addVaryHttpHeader('Cookie');
$this->getResponse()->addVaryHttpHeader('User-Agent');
$this->getResponse()->addVaryHttpHeader('Accept-Language');
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30